{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "DkA0Fobtb9dM"
   },
   "source": [
    "##### Copyright 2022 The Cirq Developers"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "cellView": "form",
    "id": "tUshu7YfcAAW"
   },
   "outputs": [],
   "source": [
    "# @title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
    "# you may not use this file except in compliance with the License.\n",
    "# You may obtain a copy of the License at\n",
    "#\n",
    "# https://www.apache.org/licenses/LICENSE-2.0\n",
    "#\n",
    "# Unless required by applicable law or agreed to in writing, software\n",
    "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
    "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
    "# See the License for the specific language governing permissions and\n",
    "# limitations under the License."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "ed597a8b13ef"
   },
   "source": [
    "# Quantum Virtual Machine"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "HDiKQEXika1y"
   },
   "source": [
    "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
    "  <td>\n",
    "    <a target=\"_blank\" href=\"https://quantumai.google/cirq/simulate/quantum_virtual_machine\"><img src=\"https://quantumai.google/site-assets/images/buttons/quantumai_logo_1x.png\" />View on QuantumAI</a>\n",
    "  </td>\n",
    "  <td>\n",
    "    <a target=\"_blank\" href=\"https://colab.research.google.com/github/quantumlib/Cirq/blob/main/docs/simulate/quantum_virtual_machine.ipynb\"><img src=\"https://quantumai.google/site-assets/images/buttons/colab_logo_1x.png\" />Run in Google Colab</a>\n",
    "  </td>\n",
    "  <td>\n",
    "    <a target=\"_blank\" href=\"https://github.com/quantumlib/Cirq/blob/main/docs/simulate/quantum_virtual_machine.ipynb\"><img src=\"https://quantumai.google/site-assets/images/buttons/github_logo_1x.png\" />View source on GitHub</a>\n",
    "  </td>\n",
    "  <td>\n",
    "    <a href=\"https://storage.googleapis.com/tensorflow_docs/Cirq/docs/simulate/quantum_virtual_machine.ipynb\"><img src=\"https://quantumai.google/site-assets/images/buttons/download_icon_1x.png\" />Download notebook</a>\n",
    "  </td>\n",
    "</table>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "CycSD8LM2A5G"
   },
   "source": [
    "The quantum virtual machine is a virtual Google quantum processor that you can run circuits on by using the [virtual engine interface](./virtual_engine_interface.ipynb). Behind this interface, it uses simulation with noise data to mimic Google quantum hardware processors with high accuracy: In internal tests, the virtual and actual hardware are within experimental error of each other. Additionally, it supports internal use of the high-performance [qsim](/qsim) simulator, for fast execution of larger circuits. The QVM should be used as a preparation step before running on Google hardware, and as a substitute for Google hardware when it is not available.\n",
    "\n",
    "If you just want to use the QVM for realistic noisy simulation, you can copy and build upon the [QVM Creation Template](./qvm_builder_code.ipynb), which provides a concise and portable way to instantiate an `Engine` class that you can realistically simulate circuit runs with. After doing so, skip forward to the [How to use a QVM](#how_to_use_a_qvm) section. If you're interested in how the QVM is prepared for use, continue on to the following section."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "p31cCK_T1ylm"
   },
   "source": [
    "## Setup"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "cellView": "form",
    "id": "43IpRYMY1Ynr"
   },
   "outputs": [],
   "source": [
    "# @title Install `cirq_google` and `qsimcirq`\n",
    "\n",
    "try:\n",
    "    import cirq\n",
    "    import cirq_google\n",
    "except ImportError:\n",
    "    print(\"installing cirq...\")\n",
    "    !pip install --quiet cirq-google\n",
    "    print(\"installed cirq.\")\n",
    "    import cirq\n",
    "    import cirq_google\n",
    "\n",
    "try:\n",
    "    import qsimcirq\n",
    "except ImportError:\n",
    "    print(\"installing qsimcirq...\")\n",
    "    !pip install --quiet qsimcirq\n",
    "    print(f\"installed qsimcirq.\")\n",
    "    import qsimcirq"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "TNz3r23U1c-H"
   },
   "source": [
    "## How to build a QVM\n",
    "\n",
    "### Choose a processor to virtualize\n",
    "\n",
    "Currently, the necessary data is publicly accessible for the [Willow](https://quantumai.google/static/site-assets/downloads/willow-spec-sheet.pdf) processor as well as the older [Weber](https://quantumai.google/hardware/datasheet/weber.pdf) and Rainbow processors. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "YaLtjwcFy4AC"
   },
   "outputs": [],
   "source": [
    "# Choose a processor (\"willow_pink\" or \"rainbow\" or \"weber\")\n",
    "# (see cirq_google.engine.list_virtual_processors() for available names)\n",
    "\n",
    "processor_id = \"willow_pink\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "rD-o-Abdy_rV"
   },
   "source": [
    "### Build a noisy simulator with a hardware noise model\n",
    "\n",
    "- Load median device noise data for the processor you have chosen. Learn more about device noise data [here](../noise/representing_noise.ipynb)\n",
    "- Transform the median device noise data to a Cirq noise properties object\n",
    "- Create a noise model using your noise properties\n",
    "- Set up a qsim sampler which runs noisy simulations using your noise model. Learn more about noisy simulation with qsim here in the [Noisy simulation with qsim page](/qsim/tutorials/noisy_qsimcirq)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "ygV7yCoBy6I9"
   },
   "outputs": [],
   "source": [
    "# Load the noise properties for the processor.\n",
    "noise_props = cirq_google.engine.load_device_noise_properties(processor_id)\n",
    "# Create a noise model from the noise properties.\n",
    "noise_model = cirq_google.NoiseModelFromGoogleNoiseProperties(noise_props)\n",
    "# Prepare a qsim simulator using the noise model.\n",
    "sim = qsimcirq.QSimSimulator(noise=noise_model)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "5HQUregUzAMk"
   },
   "source": [
    "The qsim documentation explains how simulation performance depends on choice of hardware. If you would like use a larger number of qubits on your virtual device (eg 25-32 qubits), parallelizing the simulation over multiple compute nodes is advised. You can do this using Google Cloud hardware as is described in the [qsim Multinode Tutorial](/qsim/tutorials/multinode).\n",
    "\n",
    "### Set up the virtual engine with a virtual processor, packaging in the noisy simulator\n",
    "To ensure that the workflow for using a virtual quantum processor is the same as the workflow for using a real quantum processor, a quantum virtual engine implements the same interface as the `cirq.Engine` for used  Google's quantum hardware. Learn more about Google’s quantum engine in the [Quantum Virtual Engine Interface page](./virtual_engine_interface.ipynb).\n",
    "- Create a device object. Learn more about the device object in Cirq here  in the [Devices page](../hardware/devices.ipynb)\n",
    "- Create a simulated processor object for the engine to consume (`SimulatedLocalProcessor`)\n",
    "- Create a virtual engine (`SimulatedLocalEngine`)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "SkhFDV7n19-4"
   },
   "outputs": [],
   "source": [
    "# Package the simulator and device in an Engine.\n",
    "# The device object\n",
    "device = cirq_google.engine.create_device_from_processor_id(processor_id)\n",
    "# Load the median device noise calibration for your processor.\n",
    "cal = cirq_google.engine.load_median_device_calibration(processor_id)\n",
    "# The simulated processor object\n",
    "sim_processor = cirq_google.engine.SimulatedLocalProcessor(\n",
    "    processor_id=processor_id, sampler=sim, device=device, calibrations={cal.timestamp // 1000: cal}\n",
    ")\n",
    "# The virtual engine\n",
    "sim_engine = cirq_google.engine.SimulatedLocalEngine([sim_processor])\n",
    "print(\n",
    "    \"Your quantum virtual machine\",\n",
    "    processor_id,\n",
    "    \"is ready, here is the qubit grid:\",\n",
    "    \"\\n========================\\n\",\n",
    ")\n",
    "print(sim_engine.get_processor(processor_id).get_device())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "3uE8x8wP2N8N"
   },
   "source": [
    "## How to use a QVM\n",
    "\n",
    "The following code runs a circuit on your QVM by using the `run` function of a sampler from the simulated engine:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "iuyahfFd2Tgl"
   },
   "outputs": [],
   "source": [
    "q0 = cirq.GridQubit(4, 4)\n",
    "q1 = cirq.GridQubit(4, 5)\n",
    "circuit = cirq.Circuit(\n",
    "    cirq.X(q0),\n",
    "    cirq.X(q1) ** 0.5,\n",
    "    cirq.CZ(q0, q1),\n",
    "    cirq.X(q1) ** 0.5,\n",
    "    cirq.measure([q0, q1], key=\"measure\"),\n",
    ")\n",
    "\n",
    "results = sim_engine.get_sampler(processor_id).run(circuit, repetitions=3000)\n",
    "\n",
    "print(results.histogram(key=\"measure\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "gll88JAl2WED"
   },
   "source": [
    "As in the example linked above, your circuit needs to be “device ready”. This means that: \n",
    "- The gates in the circuit need to be in the set of legal gates on the device\n",
    "- The circuit needs to operate on qubits available on the virtual device. \n",
    "- The topology of your circuit must correspond to the topology of the device (i.e., 2-qubit gates must act on adjacent qubits).\n",
    "\n",
    "For a hands-on example of the steps necessary to prepare a circuit to be run on the QVM, see the [QVM Basic Example](./qvm_basic_example.ipynb) page.\n",
    "\n",
    "The steps necessary to make a circuit device-ready are summarized here:\n",
    "1. Transform your circuit to use the correct gate set with `cirq.optimize_for_target_gateset`. Read [Transformers](../transform/transformers.ipynb) for more on how to modify circuits. \n",
    "2. Choose qubits on the virtual device for your circuit to run on. The connectivity required by your circuit must be supported by the connectivity present in your chosen qubit set. See [Qubit Picking](../hardware/qubit_picking.ipynb) for more advice.\n",
    "3. Map your transformed circuit to those qubits with `cirq.Circuit`'s `transform_qubits` function. This may require some careful planning depending on your particular circuit. \n",
    "\n",
    "You also need to decide on the number of repetitions your circuit will be used in the trajectory simulation. This number determines how accurately the quantum virtual machine will simulate the true quantum state of your circuit. For more details on this see [this paper](https://arxiv.org/abs/2111.02396){:.external}. We recommend using 10,000+ repetitions for research simulations, and 3,000 repetitions for learning simulations. If you are just getting a feel for the tools you can set the number of repetitions lower temporarily (eg 1 to 10) to speed things up.\n"
   ]
  }
 ],
 "metadata": {
  "colab": {
   "collapsed_sections": [],
   "name": "quantum_virtual_machine.ipynb",
   "toc_visible": true
  },
  "kernelspec": {
   "display_name": "Python 3",
   "name": "python3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
